package de.hwr.sudokuspielehr.data;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import java.awt.Point;
import java.util.Arrays;
import java.util.List;

import org.junit.Test;

/**
 * Tests Sudoku class.
 * 
 * @author J. Reischauer
 * 
 */
public class TestSudoku {

	@Test
	public void testScan() {
		Sudoku sudokuUnderTest = new Sudoku();

		sudokuUnderTest.setCell(0, 0, 1);
		sudokuUnderTest.setCell(1, 0, 3);
		sudokuUnderTest.setCell(2, 0, 4);
		sudokuUnderTest.setCell(1, 2, 5);
		sudokuUnderTest.setCell(2, 2, 6);

		sudokuUnderTest.setCell(3, 1, 2);
		sudokuUnderTest.setCell(3, 2, 7);
		sudokuUnderTest.setCell(4, 2, 8);

		sudokuUnderTest.setCell(8, 1, 4);

		sudokuUnderTest.setCell(0, 4, 3);
		sudokuUnderTest.setCell(0, 5, 4);

		sudokuUnderTest.setCell(3, 3, 3);
		sudokuUnderTest.setCell(3, 4, 4);

		sudokuUnderTest.setCell(7, 5, 7);

		sudokuUnderTest.setCell(2, 7, 5);

		sudokuUnderTest.setCell(5, 7, 8);

		sudokuUnderTest.setCell(8, 6, 3);
		sudokuUnderTest.setCell(7, 8, 4);

		sudokuUnderTest.print();
		sudokuUnderTest.scan();
		sudokuUnderTest.print();
	}

	@Test
	public void testGetGroup() {
		Sudoku sudokuUnderTest = new Sudoku();
		sudokuUnderTest.setCell(0, 0, 5);
		sudokuUnderTest.setCell(1, 0, 3);

		int[][] expected = { { 5, -1, -1 }, { 3, -1, -1 }, { -1, -1, -1 } };
		int[][] actual = sudokuUnderTest.getGroup(0, 0);

		for (int i = 0; i < 3; i++) {
			for (int j = 0; j < 3; j++) {
				assertEquals(expected[i][j], actual[i][j]);
			}
		}

		RuntimeException actualException = null;
		try {
			sudokuUnderTest.getGroup(4, 0);
		} catch (RuntimeException r) {
			actualException = r;
		}

		assertTrue(actualException != null);
	}

	@Test
	public void testSudoku() {
		Sudoku s = new Sudoku();
		int expected = Sudoku.EMPTY_CELL_VALUE;

		for (int actual : s.getBoard()) {
			assertEquals(expected, actual);
		}
	}

	@Test
	public void testGetCellSetCell() {
		Sudoku s = new Sudoku();

		Point point = new Point(0, 0);
		int value = 1;

		s.setCell(point.x, point.y, value);

		int expected = value;
		int actual = s.getCell(point.x, point.y);

		assertEquals(expected, actual);
	}

	@Test
	public void testUnsetBoard() {
		Sudoku s = new Sudoku();

		Point point1 = new Point(0, 0);
		Point point2 = new Point(1, 0);
		int value1 = 1;
		int value2 = 2;

		s.setCell(point1.x, point1.y, value1);
		s.setCell(point2.x, point2.y, value2);

		s.unsetBoard();

		int expectedValue1 = Sudoku.EMPTY_CELL_VALUE;
		int expectedValue2 = Sudoku.EMPTY_CELL_VALUE;

		int actualValue1 = s.getCell(point1.x, point1.y);
		int actualValue2 = s.getCell(point2.x, point2.y);

		assertEquals(expectedValue1, actualValue1);
		assertEquals(expectedValue2, actualValue2);
	}

	@Test
	public void testSolve() {
		Sudoku sudokuUnderTest = new Sudoku();
		sudokuUnderTest.solve();
		assertFalse(sudokuUnderTest.containsErrors());
	}

	@Test
	public void testGetPossibleNumbers() {
		Sudoku sudokuUnderTest = new Sudoku();
		sudokuUnderTest.setCell(0, 0, 1);
		sudokuUnderTest.setCell(2, 0, 2);
		sudokuUnderTest.setCell(2, 2, 3);

		List<Integer> expected = Arrays.asList(4, 5, 6, 7, 8, 9);
		List<Integer> actual = sudokuUnderTest.getPossibleNumbers(1, 1);

		assertEquals(expected, actual);
	}

	@Test
	public void testContainsErrors() {
		Sudoku sudokuUnderTest = new Sudoku();

		sudokuUnderTest.setCell(0, 0, 1);
		sudokuUnderTest.setCell(1, 0, 2);

		boolean expected = false;
		boolean actual = sudokuUnderTest.containsErrors();

		assertEquals(expected, actual);

		sudokuUnderTest.setCell(1, 1, 1);

		expected = true;
		actual = sudokuUnderTest.containsErrors();

		assertEquals(expected, actual);

		sudokuUnderTest.setCell(1, 1, 3);
		sudokuUnderTest.setCell(7, 0, 1);

		expected = true;
		actual = sudokuUnderTest.containsErrors();

		assertEquals(expected, actual);

		sudokuUnderTest.setCell(7, 0, 4);
		sudokuUnderTest.setCell(0, 5, 1);

		expected = true;
		actual = sudokuUnderTest.containsErrors();

		assertEquals(expected, actual);
	}

	@Test
	public void testGetNextEmptyCell() {
		Sudoku sudokuUnderTest = new Sudoku();

		sudokuUnderTest.setCell(0, 0, 1);
		sudokuUnderTest.setCell(1, 0, 2);

		Point expected = new Point(2, 0);
		Point actual = sudokuUnderTest.getNextEmptyCell(0, 0);

		sudokuUnderTest.print();
		System.out.println(sudokuUnderTest.getCell(0));
		System.out.println(sudokuUnderTest.getCell(1));
		assertEquals(expected, actual);

		sudokuUnderTest.setCell(7, 8, 2);
		sudokuUnderTest.setCell(8, 8, 1);

		expected = Sudoku.DEFAULT_COORD;
		actual = sudokuUnderTest.getNextEmptyCell(7, 8);

		assertEquals(expected, actual);

		expected = new Point(4, 4);
		actual = sudokuUnderTest.getNextEmptyCell(3, 4);

		assertEquals(expected, actual);
	}

	@Test
	public void testAutoFill() {
		Sudoku sudokuUnderTest = new Sudoku();

		sudokuUnderTest.setCell(0, 0, 4);
		sudokuUnderTest.setCell(1, 0, 7);
		sudokuUnderTest.setCell(2, 0, 9);
		sudokuUnderTest.setCell(3, 0, 8);
		sudokuUnderTest.setCell(4, 0, 1);
		sudokuUnderTest.setCell(5, 0, 2);
		sudokuUnderTest.setCell(6, 0, 3);
		sudokuUnderTest.setCell(7, 0, 6);
		sudokuUnderTest.setCell(8, 0, 5);

		sudokuUnderTest.setCell(0, 1, 6);
		sudokuUnderTest.setCell(1, 1, 2);
		sudokuUnderTest.setCell(2, 1, 8);
		sudokuUnderTest.setCell(3, 1, 3);
		sudokuUnderTest.setCell(4, 1, 5);
		sudokuUnderTest.setCell(5, 1, 4);
		sudokuUnderTest.setCell(6, 1, 1);
		sudokuUnderTest.setCell(7, 1, 9);
		sudokuUnderTest.setCell(8, 1, 7);

		sudokuUnderTest.setCell(0, 2, 5);
		sudokuUnderTest.setCell(1, 2, 3);
		sudokuUnderTest.setCell(2, 2, 1);
		sudokuUnderTest.setCell(3, 2, 6);
		sudokuUnderTest.setCell(4, 2, 9);
		sudokuUnderTest.setCell(5, 2, 7);
		sudokuUnderTest.setCell(6, 2, 2);
		sudokuUnderTest.setCell(7, 2, 8);
		sudokuUnderTest.setCell(8, 2, 4);

		sudokuUnderTest.setCell(0, 3, 3);
		sudokuUnderTest.setCell(1, 3, 9);
		sudokuUnderTest.setCell(2, 3, 5);
		sudokuUnderTest.setCell(3, 3, 4);
		sudokuUnderTest.setCell(4, 3, 6);
		sudokuUnderTest.setCell(5, 3, 1);
		sudokuUnderTest.setCell(6, 3, 8);
		sudokuUnderTest.setCell(7, 3, 7);
		sudokuUnderTest.setCell(8, 3, 2);

		sudokuUnderTest.setCell(0, 4, 8);
		sudokuUnderTest.setCell(1, 4, 6);
		sudokuUnderTest.setCell(2, 4, 2);
		sudokuUnderTest.setCell(3, 4, 7);
		// sudokuUnderTest.setCell(4, 4, 3);
		Point expected1Point = new Point(4, 4);
		int expected1Value = 3;

		sudokuUnderTest.setCell(5, 4, 9);
		sudokuUnderTest.setCell(6, 4, 4);
		sudokuUnderTest.setCell(7, 4, 5);
		sudokuUnderTest.setCell(8, 4, 1);

		sudokuUnderTest.setCell(0, 5, 1);
		sudokuUnderTest.setCell(1, 5, 4);
		sudokuUnderTest.setCell(2, 5, 7);
		// sudokuUnderTest.setCell(3, 5, 2);
		Point expected2Point = new Point(3, 5);
		int expected2Value = 2;

		sudokuUnderTest.setCell(4, 5, 8);
		sudokuUnderTest.setCell(5, 5, 5);
		sudokuUnderTest.setCell(6, 5, 6);
		sudokuUnderTest.setCell(7, 5, 3);
		// sudokuUnderTest.setCell(8, 5, 9);
		Point expected3Point = new Point(8, 5);
		int expected3Value = 9;

		sudokuUnderTest.setCell(0, 6, 7);
		sudokuUnderTest.setCell(1, 6, 5);
		sudokuUnderTest.setCell(2, 6, 3);
		sudokuUnderTest.setCell(3, 6, 1);
		// sudokuUnderTest.setCell(4, 6, 4);
		Point expected4Point = new Point(4, 6);
		int expected4Value = 4;

		sudokuUnderTest.setCell(5, 6, 8);
		sudokuUnderTest.setCell(6, 6, 9);
		sudokuUnderTest.setCell(7, 6, 2);
		sudokuUnderTest.setCell(8, 6, 6);

		sudokuUnderTest.setCell(0, 7, 9);
		sudokuUnderTest.setCell(1, 7, 1);
		sudokuUnderTest.setCell(2, 7, 6);
		sudokuUnderTest.setCell(3, 7, 5);
		sudokuUnderTest.setCell(4, 7, 2);
		sudokuUnderTest.setCell(5, 7, 3);
		sudokuUnderTest.setCell(6, 7, 7);
		sudokuUnderTest.setCell(7, 7, 4);
		sudokuUnderTest.setCell(8, 7, 8);

		sudokuUnderTest.setCell(0, 8, 2);
		sudokuUnderTest.setCell(1, 8, 8);
		sudokuUnderTest.setCell(2, 8, 4);
		// sudokuUnderTest.setCell(3, 8, 9);
		Point expected5Point = new Point(3, 8);
		int expected5Value = 9;

		sudokuUnderTest.setCell(4, 8, 7);
		sudokuUnderTest.setCell(5, 8, 6);
		sudokuUnderTest.setCell(6, 8, 5);
		sudokuUnderTest.setCell(7, 8, 1);
		sudokuUnderTest.setCell(8, 8, 3);

		sudokuUnderTest.fillAllObviousCells();

		int actual1Value = sudokuUnderTest.getCell(expected1Point.x, expected1Point.y);
		int actual2Value = sudokuUnderTest.getCell(expected2Point.x, expected2Point.y);
		int actual3Value = sudokuUnderTest.getCell(expected3Point.x, expected3Point.y);
		int actual4Value = sudokuUnderTest.getCell(expected4Point.x, expected4Point.y);
		int actual5Value = sudokuUnderTest.getCell(expected5Point.x, expected5Point.y);

		assertEquals(expected1Value, actual1Value);
		assertEquals(expected2Value, actual2Value);
		assertEquals(expected3Value, actual3Value);
		assertEquals(expected4Value, actual4Value);
		assertEquals(expected5Value, actual5Value);
	}
}
